#ifndef __MY__SERVICE__
#define __MY__SERVICE__

#include "httplib.h"
#include "data.hpp"
#include "util.hpp"
#include "config.hpp"

extern cloud::DataManager* _data;
namespace cloud{
    class Service{
        public:
            Service(){
                Config* config = Config::GetInstance();
                _server_ip = config->GetServerIp();
                _server_port = config->GetServerport();
                _download_prefix = config->GetDownLoadPrefix();
            };
            bool RunModule(){
                _server.Post("/upload", Upload);
                _server.Get("/listshow", ListShow);
                _server.Get("/", ListShow);
                std::string download_url = _download_prefix + "(.*)";
                _server.Get(download_url, Download);
                _server.listen("0.0.0.0", _server_port);
            }
        private:
            static void Upload(const httplib::Request& req, httplib::Response& rsp){
                // post/upload 文件数据在正文中（正文并不全是文件数据）
                // 打印HTTP请求信息
                std::cout << "HTTP请求信息：" << std::endl;
                std::cout << "Method: " << req.method << std::endl;
                std::cout << "Path: " << req.path << std::endl;
                std::cout << "Headers:" << std::endl;
                for (const auto &header : req.headers)
                {
                    std::cout << header.first << ": " << header.second << std::endl;
                }

                std::cout << "Files:" << std::endl;
                for (const auto &file : req.files)
                {
                    const std::string &fileFieldName = file.first;
                    const httplib::MultipartFormData &fileData = file.second;

                    std::cout << "Field Name: " << fileFieldName << std::endl;
                    std::cout << "File Name: " << fileData.filename << std::endl;
                    std::cout << "Content Type: " << fileData.content_type << std::endl;
                    std::cout << "Content Length: " << fileData.content.length() << std::endl;
                    // 请注意，文件内容可能很大，不建议直接打印
                    // std::cout << "Content: " << fileData.content << std::endl;
                }


                auto ret = req.has_file("file");
                if(ret == false){
                    std::cout << "http请求中没有file字段" << std::endl; /////////////////////////////////////////
                    rsp.status = 400;
                    return;
                }
                const auto& file = req.get_file_value("file");
                std::string back_dir = Config::GetInstance()->GetBackDir();
                std::string realpath = back_dir + FileUtil(file.filename).Filename();
                FileUtil fu(realpath);
                fu.SetContent(file.content);//将上传来的文件数据写入到服务器备份文件中
                BackupInfo info;
                info.NewBackupInfo(realpath);//组织备份文件信息
                _data->Insert(info);

            }
            //将时间戳格式的时间转换成时分秒的时间
            static std::string TimeToStr(time_t t){
                std::string tmp = std::ctime(&t);
                return tmp;
            }
            static void ListShow(const httplib::Request& req, httplib::Response& rsp){
                //1.获取所有文件的备份信息
                std::vector<BackupInfo> arry;
                _data->GetAll(&arry);
                //2.根据所有备份信息，组织html文件数据
                std::stringstream ss;
                ss << "<html><head><title>Download</title></head>";
                ss << "<body><h1><Download></h1><table>";
                for(auto& a : arry){
                    ss << "<tr>";
                    std::string filename = FileUtil(a.real_path).Filename();
                    ss << "<td><a href='" << a.url << "'>" << filename << "</a></td>";
                    ss << "<td align='right'>" << TimeToStr(a.mtime) << "</td>";
                    ss << "<td align='right'>" << a.fsize / 1024 << "k<td>";
                    ss << "</tr>";
                }
                    ss << "</table></body></html>";
                    rsp.body = ss.str();
                    rsp.set_header("Content-Type", "text/html; charset=utf-8");
                    rsp.status = 200;
            }
            static std::string GetETag(const BackupInfo& info){
                // etg : filename-fi
                FileUtil fu(info.real_path);
                std::string etag = fu.Filename();
                etag += "-";
                etag += std::to_string(info.fsize);
                etag += "-";
                etag += std::to_string(info.mtime);
                return etag;
            }
            static void Download(const httplib::Request& req, httplib::Response& rsp){
                //1.获取客户端请求的资源路径path， req.path
                //2.根据资源路径，获取文件备份信息
                BackupInfo info;
                _data->GetOneByURL(req.path, &info);
                //3.判断文件是否被压缩，如果压缩则需要解压缩
                if(info.pack_flag == true){
                    FileUtil fu(info.pack_path);
                    fu.UnCompress(info.real_path);//将文件解压到备份目录下
                    //删除压缩包修改，修改备份信息
                    fu.Remove();
                    info.pack_flag = false;
                    _data->Updata(info);
                }
                
                bool retrans = false; //断点续传标志位
                std::string old_etag;
                if(req.has_header("If-Range")){
                    old_etag = req.get_header_value("If-Range");
                    //有If-Range 字段，且这个字段的值与请求文件的最新Etag一致，则符合断点续传
                    if(old_etag == GetETag(info)){
                        retrans = true;
                    }
                    std::cout << "old_etag:" << old_etag << std::endl << "new_etag:" << GetETag(info) << std::endl;
                }

                //读取文件数据，放入rsp.body中
                FileUtil fu(info.real_path);
                if(retrans == false){ //下载完整文件
                    fu.GetContent(&rsp.body);
                    // 5.设置响应头部字段： ETag， Accept-Range: bytes
                    rsp.set_header("Accept-Ranges", "bytes");
                    rsp.set_header("ETag", GetETag(info));
                    rsp.set_header("Content-Type", "application/octet-stream"); // 表明此时是下载文件的方式
                    // rsp.set_header("Content-Disposition", "attachment; filename=\"" +
                    //     FileUtil(info.real_path).Filename() + "\"");
                    rsp.status = 200;
                }
                else{ //断点续传
                    //httplib内部实现了对于区间请求也就是断点续传请求的处理
                    //只需要我们用户将文件所有数据读取到rsp.body中，它内部会
                    //自动根据请求区间，从body中取出指定区间数据进行响应
                    // std::string range = req.get_header_val("Range"); bytes=start-end
                    fu.GetContent(&rsp.body);
                    // 5.设置响应头部字段： ETag， Accept-Range: bytes
                    rsp.set_header("Accept-Ranges", "bytes");
                    rsp.set_header("ETag", GetETag(info));
                    rsp.set_header("Content-Type", "application/octet-stream"); // 表明此时是下载文件的方式  
                    //rsp.set_header("Content-Range", "bytes start-end/fsize");
                    rsp.status = 206;//区间请求响应的是206状态码
                }
            }
        private:
            int _server_port;
            std::string _server_ip;
            std::string _download_prefix;
            httplib::Server _server;
    };
}


#endif